#include <iostream>

using namespace std;

#include "Memory.h"

Memory::CacheStack::CacheStack () {
	this->setNum = 1;
	nhit = nmiss = 0;

	for (int i = 0; i < 16; i++)
		tags[i] = 0;
}
Memory::CacheStack::CacheStack (int setNum) {
	this->setNum = setNum;
	this->nhit = this->nmiss = 0;

	/* init tags array to zero, so that
	 * we know that the values are invalid
	 */
	for (int i = 0; i < 16; i++)
	tags[i] = 0;
}
			
int& Memory::CacheStack::operator[] (int index) {
	int i = index % (16/setNum);
	
	if (index < 0 || index > 255)
	errprintline("Segmentation Fault", -1);
					
	if((tags[i] & VALID) && (tags[i] & INDEX)==index) {

		tags[i] |= WRITE;
		nhit++;
		return frame[i];
	} else if (setNum == 2 && (tags[8+i] & VALID) && 
			(tags[8+i] & INDEX)==index) {
		tags[8+i] |= WRITE;
		nhit++;
		return frame[8+i];
	} else {
		int j = i;
		if ((tags[i] & VALID) && (!(tags[8+i] & VALID))) j = 8+i;
		else if ((!(tags[i] & VALID)) && (tags[8+i] & VALID)) j = i;
		else j = i;
		
		if ((tags[j] & VALID) && (tags[j] & WRITE))
		mainMem[tags[j] & INDEX] = frame[j];
						
		frame[j] = mainMem[index];
		tags[j] = index;
		tags[j] |= VALID;
		tags[j] |= WRITE;
		nmiss++;
		return frame[j];
	}
}

Memory::Memory ()
{
	Memory(1);
}

Memory::Memory (int setNum):Stack(setNum)
{
	immedValue = 0;
	nhit = &Stack.nhit;
	nmiss = &Stack.nmiss;
}

Memory::~Memory ()
{
}

int Memory::pushInstruction (string instr)
{
	Text.insert (Text.end(), instr);
	return 0;
}

int Memory::insertInstruction (int index, string instr)
{
	vector<string>::iterator p = Text.begin ();
	if (index < static_cast<int>(Text.size())) {
	       	p = p + index;
		Text.insert (p, instr);
		return 0;
	}
	return -1;
}

string Memory::getInstruction (int index)
{
	if (index < static_cast<int>(Text.size()))
		return Text[index];
	else 
		return NULL;
}

int Memory::modifyInstruction (int index, string instr)
{
	if (index < static_cast<int>(Text.size())) {
		Text[index] = instr;
		return 0;
	} 
	else 
		return -1;
}

void Memory::SelectMemLocation (int memloc)
{
	if (memloc >=0 && memloc <=255)
	selectMemLoc = memloc;
	else
		errprint ("segfault - SelectMemLocation");
}

int Memory::ReadFromStack (int index)
{
	if (index >= 0 && index <= 255)
		return Stack[index];
	else {
		errprint ("Segfault - ReadFromStack");
		return -1;
	}
}

int Memory::ReadFromSelectedLoc ()
{
	if (selectMemLoc >= 0 && selectMemLoc < 256)
		return Stack [ selectMemLoc ];
	else {
		errprint ("Segfault - ReadFromSelectedLoc");
		return -1;
	}
}

int Memory::WriteToStack (int index, int value)
{
	if (index >= 0 && index <256)
		Stack[index] = value;
	else {
		errprint ("Segfault - WriteToStack");
		return -1;
	}
	return 0;
}

int Memory::WriteToSelectedLoc (int value)
{
	if (selectMemLoc >= 0 && selectMemLoc <= 255)
		Stack[selectMemLoc] = value;
	else
		errprint ("Segfault - WriteToSelectedLoc");
	return 0;
}

void Memory::WriteImmedValue (int value)
{
	immedValue = value;
}

int Memory::ReadImmedValue ()
{
	return immedValue;
}

void Memory::errprint (const char *msg)
{
	errprintline (msg, -1);
}
